import mysql from 'mysql2/promise'
import { Connection } from "./Connection"

export class DataSource {

  // private static instance: DataSource
  //
  // public static getInstance(): DataSource {
  //   if (!DataSource.instance) {
  //     DataSource.instance = new DataSource()
  //   }
  //
  //   return DataSource.instance
  // }
  //
  // private connectionPool
  //
  // private constructor() {
  //   const mysqlConfig = {
  //     // 服务器地址
  //     host: '127.0.0.1',
  //     // 端口
  //     port: 3306,
  //     // 数据库编码默认采用utf8/utf8mb4
  //     charset: 'utf8mb4',
  //     // 数据库名
  //     database: 'beers',
  //     // 用户名
  //     user: 'root',
  //     // 密码
  //     password: '123456',
  //     connectTimeout: 10000,
  //     supportBigNumbers: true,
  //     bigNumberStrings: true,
  //     // 同时使用多条查询语句
  //     multipleStatements: true,
  //     // https://stackoverflow.com/questions/71949351/how-to-use-named-parameters-in-node-mysql2-prepared-statements
  //     namedPlaceholders: true,
  //     waitForConnections: true,
  //     connectionLimit: 16,
  //     queueLimit: 0
  //   }
  //   this.connectionPool = mysql.createPool(mysqlConfig)
  //   console.log(`DataSource connect Mysql success! => `, mysqlConfig)
  //   this.connectionPool.on('connection',  function (conn) {
  //     console.log(`DataSource onConnection SET AUTOCOMMIT = 0`)
  //     conn.query('SET AUTOCOMMIT = 0')
  //   })
  // }
  private static connectionId: number = 1
  private connectionPool

  // https://github.com/sidorares/node-mysql2/blob/master/lib/connection_config.js
  // https://github.com/sidorares/node-mysql2/blob/master/lib/pool.js
  constructor(mysqlConfig) {
    this.connectionPool = mysql.createPool(mysqlConfig)
    // console.log(`DataSource connect Mysql success! => user = `, mysqlConfig.user)
    this.connectionPool.on('connection', (connection: Connection) => {
      connection.id = DataSource.connectionId++
      // console.log(`getConnection from Pool connectionId = ${connection.id}`)
      const originalRelease = connection.release
      connection.release =  () => {
        if (connection.isActive) {
          // TODO 编码方式实现的连接不自动提交：恢复
          // await connection.query('SET AUTOCOMMIT = 0')
          originalRelease.apply(connection)
        }
      }
      /**
       * SET AUTOCOMMIT = 0
       * 关闭自动提交后，该位置会作为一个事务起点，直到执行 COMMIT 语句和 ROLLBACK 语句后，该事务才结束。
       * 如果不提交事务，而终止 MySQL 会话，数据库将会自动执行回滚操作。
       *
       * 使用 BEGIN 或 START TRANSACTION 开启一个事务之后，自动提交将保持禁用状态，直到使用 COMMIT 或 ROLLBACK 结束事务。
       * 提交模式会恢复到之前的状态，即
       *  如果 BEGIN 前 autocommit = 1，则完成本次事务后 autocommit 还是 1。
       *  如果 BEGIN 前 autocommit = 0，则完成本次事务后 autocommit 还是 0。
       *
       *   show variables like "autocommit";
       *   set autocommit = 0;
       *
       *   set global autocommit = 0;
       *   或者修改 my.cfg
       *   [mysqld]
       *   autocommit=0
       *
       *   https://dev.mysql.com/doc/refman/5.6/en/innodb-autocommit-commit-rollback.html
       */
    })
    this.connectionPool.on('acquire', (connection: Connection) => {
      // console.log(`connectionPool on acquire connectionId = ${connection.id}`)
      connection.isActive = true
    })
    this.connectionPool.on('release', (connection: Connection) => {
      // console.log(`connectionPool on release connectionId = ${connection.id}`)
      connection.isActive = false
    })
  }

  async getConnection(): Promise<Connection> {
    const connection = await this.connectionPool.getConnection()
    // TODO 编码方式实现的连接不自动提交
    // 1）connectionPool.on('connection') 获取默认 AUTOCOMMIT 值(A)，对比设置（mysqlConfig）的 AUTOCOMMIT 值(B)
    // 2）Datasource.getConnection 获取连接后，如果 A != B，则 SET AUTOCOMMIT = B
    // 3) 调用 connection.release 时 ，如果 A != B，则 SET AUTOCOMMIT = A
    // await connection.query('SET AUTOCOMMIT = 0')
    return connection
  }
}
